package webserver.bank;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.util.StringTokenizer;

import webserver.standard.Handler;
import webserver.standard.Server;

public class RPCHandlerJGroup implements Handler
{
	String firstLine;
	GenericClassCaller gcc;
	GenericObjectCreater goc;
	String httpversion = "HTTP/1.0";
	Server server;

	public RPCHandlerJGroup(Server server, String firstLine)
	{
		this.server = server;
		// remove the http version
		this.firstLine = firstLine.substring(0, firstLine.length() - 8);
		gcc = new GenericClassCallerImpl();
		goc = new GenericObjectCreaterImpl();
	}

	private Object makeConstructorParameters(String s, String nextToken)
	{
		if (s.equals("java.lang.String"))
			return nextToken;
		else if (s.equals("double"))
			return new Double(nextToken);
		else if (s.equals("int"))
			return new Integer(nextToken);
		else if (s.equals("byte"))
			return new Byte(nextToken);
		else if (s.equals("short"))
			return new Short(nextToken);
		else if (s.equals("long"))
			return new Long(nextToken);
		else if (s.equals("char"))
			return nextToken.charAt(0);
		else if (s.equals("float"))
			return new Float(nextToken);
		else if (s.equals("boolean"))
			return new Boolean(nextToken);
		else
			return server.getObject(new Integer(nextToken));
	}

	private String[] parseLine(String line, String del)
	{
		StringTokenizer st = new StringTokenizer(line, del);
		String[] linesParsed = new String[st.countTokens()];
		int i = 0;
		while (st.hasMoreTokens())
		{
			linesParsed[i] = st.nextToken();
			i++;
		}
		return linesParsed;
	}

	private void processGETRequest() throws SecurityException,
			IllegalArgumentException, ClassNotFoundException,
			InstantiationException, IllegalAccessException,
			NoSuchMethodException, InvocationTargetException, IOException
	{
		Object o;
		Integer objectNumber;
		String[] parameterTypes = null;
		Object[] parameterValue = null;
		String[] parsedLines = parseLine(firstLine, "/");

		if (parsedLines.length >= 4)
		// parsed lines would consist f.ex. bank std.bank.AccountImpl 4 toString
		{
			objectNumber = new Integer(parsedLines[2]);

			o = server.getObject(objectNumber);
			if (o != null)
			{
				String method = parsedLines[3];

				if (parsedLines.length == 5) // checks if there's parameters
				{
					String parameters = parsedLines[4];

					String[] parameterTokens = parseLine(parameters, "&");

					parameterTypes = new String[parameterTokens.length];
					parameterValue = new Object[parameterTokens.length];
					String s;
					int j;
					StringTokenizer st;

					for (j = 0; j < parameterTypes.length; j++)
					{
						st = new StringTokenizer(parameterTokens[j], "=");
						s = parameterTypes[j] = st.nextToken();
						parameterValue[j] = makeConstructorParameters(s, st
								.nextToken());
					}
				}
				Object newObject = gcc.callClass(o, method, parameterValue,
						parameterTypes);

				if (newObject != null)
				{
					if (!(newObject.getClass().equals(java.lang.String.class)
							|| newObject.getClass().equals(Double.class)
							|| newObject.getClass().equals(Integer.class)
							|| newObject.getClass().equals(Long.class)
							|| newObject.getClass().equals(Float.class)
							|| newObject.getClass().equals(Byte.class)
							|| newObject.getClass().equals(Short.class)
							|| newObject.getClass().equals(Character.class) || newObject
							.getClass().equals(Boolean.class)))
					{
						server.addObject(newObject);
					}
				}

			}
		}
	}

	private void processPOSTRequest() throws IOException, SecurityException,
			IllegalArgumentException, ClassNotFoundException,
			InstantiationException, IllegalAccessException,
			NoSuchMethodException, InvocationTargetException
	{
		Object o;
		Integer objectNumber;
		Object[] constructorParameters = null;
		String[] constructorParameterTypes = null;
		String[] requestTokens = parseLine(firstLine, "/");
		if (requestTokens.length >= 3)
		{
			String[] parameterTokens = parseLine(requestTokens[2], "&");
			constructorParameters = new Object[parameterTokens.length];
			constructorParameterTypes = new String[parameterTokens.length];
			String s;
			int j;
			StringTokenizer st;
			for (j = 0; j < parameterTokens.length; j++)
			{
				st = new StringTokenizer(parameterTokens[j], "=");
				s = constructorParameterTypes[j] = st.nextToken();
				constructorParameters[j] = makeConstructorParameters(s, st
						.nextToken());
			}
		}
		o = goc.createObject(requestTokens[1], constructorParameters,
				constructorParameterTypes);

		server.addObject(o);
	}

	@Override
	public void run()
	{
		try
		{
			if (firstLine.startsWith("POST"))
			{
				firstLine = firstLine.substring((firstLine.indexOf(" ") + 1),
						firstLine.lastIndexOf(" "));
				processPOSTRequest();
			}
			else if (firstLine.startsWith("GET"))
			{
				firstLine = firstLine.substring((firstLine.indexOf(" ") + 1),
						firstLine.lastIndexOf(" "));
				processGETRequest();
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (SecurityException e)
		{
			e.printStackTrace();
		}
		catch (IllegalArgumentException e)
		{
			e.printStackTrace();
		}
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (InstantiationException e)
		{
			e.printStackTrace();
		}
		catch (IllegalAccessException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (NoSuchMethodException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (InvocationTargetException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
